package com.zdgk.core.control.forward.modbus;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.intelligt.modbus.jlibmodbus.Modbus;
import com.intelligt.modbus.jlibmodbus.data.ModbusHoldingRegisters;
import com.intelligt.modbus.jlibmodbus.serial.SerialParameters;
import com.intelligt.modbus.jlibmodbus.serial.SerialPort;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlave;
import com.intelligt.modbus.jlibmodbus.slave.ModbusSlaveFactory;
import com.intelligt.modbus.jlibmodbus.tcp.TcpParameters;
import com.zdgk.core.control.config.ControlConfigInfo;
import com.zdgk.core.control.read.modbus.cache.DeviceRegisterCacheResult;
import com.zdgk.core.control.read.modbus.cache.entity.RuleValueEntity;
import com.zdgk.core.licence.CheckWrapper;
import com.zdgk.core.licence.LicenceUtil;
import com.zdgk.core.web.service.ConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
public class ModbusSlaveConfig implements DisposableBean {

    private ModbusSlave slave;
    @Resource
    private ConfigService configService;
    private String machineCode;
    private ControlConfigInfo controlConfigInfo;

    @Value("${cc.license.key}")
    private String licenseKey;

    @PostConstruct
    public void init() {
        try {
            machineCode = LicenceUtil.createMachineCode();
            controlConfigInfo = configService.getControlKey();
            openSlave();
        } catch (Exception e) {
            log.error("模拟从站启动失败");
        }

    }

    private boolean openSlave() {
        try {
            if (slave != null && slave.isListening()) {
                slave.shutdown();
                slave = null;
            }
            if ("serial".equals(controlConfigInfo.getSlaveMode())) {
                SerialParameters params = new SerialParameters();
                params.setDevice(controlConfigInfo.getSlaveName()); // 串口名称
                params.setBaudRate(SerialPort.BaudRate.getBaudRate(controlConfigInfo.getSlaveBaudRate())); // 波特率
                params.setDataBits(8); // 数据位
                params.setStopBits(1); // 停止位
                params.setParity(SerialPort.Parity.getParity(0)); // 无校验
                slave = ModbusSlaveFactory.createModbusSlaveRTU(params);
                slave.setReadTimeout(60 * 1000);
                buildRuleAndData();
                slave.listen();
                if (!slave.isListening()) {
                    log.error("Modbus-Rtu-Slave【{}】启动失败", controlConfigInfo.getSlaveName());
                } else {
                    log.info("Modbus-Rtu-Slave【{}】启动成功", controlConfigInfo.getSlaveName());
                    return true;
                }
            } else {
                TcpParameters params = new TcpParameters();
                InetAddress address = InetAddress.getByName("0.0.0.0");
                params.setHost(address);
                params.setPort(controlConfigInfo.getSlavePort());
                params.setKeepAlive(true);
                slave = ModbusSlaveFactory.createModbusSlaveTCP(params);
                slave.setReadTimeout(60 * 1000);
                buildRuleAndData();
                log.info("开始启动Modbus TCP从站...");
                slave.listen();
                log.info("Modbus TCP从站已停止监听。");
                if (!slave.isListening()) {
                    log.error("Modbus-Tcp-Slave【{}】:{}启动失败", "本机", controlConfigInfo.getSlavePort());
                } else {
                    log.info("Modbus-Tcp-Slave【{}】:{}启动成功", "本机", controlConfigInfo.getSlavePort());
                    return true;
                }
            }
        } catch (Exception e) {
            log.error("从站启动失败：{}", e.getMessage());
        }
        return false;

    }

    private void buildRuleAndData() throws Exception {
        SlaveCache.slaveCacheData.clear();
        //初始化展示数据
        if (StrUtil.isNotEmpty(controlConfigInfo.getSlaveRule())) {
            JSONObject jsonObject = JSONUtil.parseObj(controlConfigInfo.getSlaveRule());
            slave.setServerAddress(jsonObject.getInt("server"));//从站
            JSONArray register = jsonObject.getJSONArray("register");
            for (int i = 0; i < register.size(); i++) {
                JSONObject registerObj = register.getJSONObject(i);
                if ("keep".equals(registerObj.getStr("value"))) {
                    JSONArray address = registerObj.getJSONArray("children");
                    for (int i1 = 0; i1 < address.size(); i1++) {
                        JSONObject addressObj = address.getJSONObject(i1);
                        if (StrUtil.isNotEmpty(addressObj.getStr("address")) && StrUtil.isNotEmpty(addressObj.getStr("buildData"))) {
                            JSONObject data = new JSONObject();
                            data.put("name", addressObj.getStr("name"));
                            data.put("address", addressObj.getInt("address"));
                            data.put("type", addressObj.getStr("type"));
                            data.put("buildData", addressObj.getStr("buildData"));
                            data.put("value", 0);
                            SlaveCache.slaveCacheData.add(data);
                        }
                    }
                }
            }
        }
        ModbusHoldingRegisters hr = new ModbusHoldingRegisters(5000);
        SlaveCache.slaveCacheData.forEach(x -> {
            try {
                hr.set(x.getInt("address"), x.getInt("value"));
            } catch (Exception e) {
            }
        });
        slave.getDataHolder().setHoldingRegisters(hr);
    }

    public void updateData() throws Exception {
//        if (!licenceCheck()) return;  //取消严验证授权逻辑
        ModbusHoldingRegisters hr = new ModbusHoldingRegisters(5000);
        SlaveCache.slaveCacheData.forEach(x -> {
            JSONArray buildData = JSONUtil.parseArray(x.getStr("buildData"));
            float ls = 0;
            for (int i = 0; i < buildData.size(); i++) {
                try {
                    JSONObject buildDataObj = buildData.getJSONObject(i);
                    String[] all = buildDataObj.getStr("address").split("-");
                    String type = all[0];
                    String address;
                    if (all.length > 2) {
                        address = all[1] + "-" + all[2];
                    }else {
                        address = all[1];
                    }

                    ArrayList<RuleValueEntity> serverData = DeviceRegisterCacheResult.ruleValueMap.get(buildDataObj.getInt("server"));
                    List<RuleValueEntity> collect = serverData.stream().filter(item ->
                            item.getRegisterType().equals(type)
                                    && item.getAddress().equals(address)
                    ).collect(Collectors.toList());
                    if (i == 0) {
                        ls = collect.get(0).getMValue();
                    } else {
                        JSONObject syg = buildData.getJSONObject(i - 1);
                        if (syg.getStr("compute").equals("+"))
                            ls = ls + collect.get(0).getRealValue();
                        if (syg.getStr("compute").equals("-"))
                            ls = ls - collect.get(0).getRealValue();
                        if (syg.getStr("compute").equals("*"))
                            ls = ls * collect.get(0).getRealValue();
                        if (syg.getStr("compute").equals("/"))
                            ls = ls / collect.get(0).getRealValue();
                    }
                } catch (Exception e) {
                    System.out.println("更新计算问题");
                }
            }
            x.put("value", ls);
            try {
                int[] ints = FloatToModbus.floatToModbusRegisters(ls, "ABCD");
                hr.set(x.getInt("address"), ints[0]);
                hr.set(x.getInt("address") + 1, ints[1]);
            } catch (Exception e) {
            }
        });
        slave.getDataHolder().setHoldingRegisters(hr);
    }

    //校验授权
    private boolean licenceCheck() throws Exception {
        CheckWrapper checkWrapper = LicenceUtil.licenceCheck(machineCode, licenseKey, LicenceUtil.static_privateKey);
        if (!checkWrapper.getCheck()) {
            log.error("授权已失效");
            destroy();
            SlaveCache.slaveCacheData.clear();
            return false;
        } else {
            return true;
        }
    }

    @Override
    public void destroy() throws Exception {
        if (isConnected()) {
            slave.shutdown();
            slave = null;
        }
    }

    public boolean isConnected() {
        return slave != null && slave.isListening();
    }


}
